package frame.options.simulation.results.sdn.graphical;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import javax.swing.Icon;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;

import model.components.links.link.BWbackupFlag;
import model.components.links.link.Link;
import model.components.links.link.SdnLink;
import model.components.links.link.VirtualLink;
import model.components.networks.sdn.SdnNetwork;
import model.components.networks.virtual.VirtualNetwork;
import model.components.nodes.node.Node;
import model.components.nodes.node.sdn.SdnNode;
import model.components.nodes.node.sdn.SdnRouter;
import model.components.nodes.node.sdn.SdnServer;
import model.components.nodes.node.sdn.SdnSwitch;
import model.components.nodes.node.virtual.VirtualMachine;
import model.components.nodes.node.virtual.VirtualNode;
import model.components.nodes.node.virtual.VirtualRouter;
import model.components.nodes.node.virtual.VirtualSwitch;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.AbstractPopupGraphMousePlugin;
import frame.options.simulation.results.ResultsFrame;
import frame.options.simulation.results.virtual.graphical.VirtualNetworkViewersPanel;

public class SdnNetworkPlugin extends AbstractPopupGraphMousePlugin implements ActionListener
{
	private SdnNode sdnNode;
	public SdnNode getSdnNode(){ return sdnNode; }
	public void setSdnNode( SdnNode sdnNode ){ this.sdnNode = sdnNode; }
	
	private JPopupMenu sdnNodePopupMenu;
	public JPopupMenu getSdnNodePopupMenu(){ return sdnNodePopupMenu; }
	public void setSdnNodePopupMenu( JPopupMenu sdnNodePopupMenu ){ this.sdnNodePopupMenu = sdnNodePopupMenu; }
	
	private SdnLink sdnLink;
	public SdnLink getSdnLink(){ return sdnLink; }
	public void getSdnLink( SdnLink sdnLink ){ this.sdnLink = sdnLink; }
	
	private JPopupMenu sdnLinkPopupMenu;
	public JPopupMenu getSdnLinkPopupMenu(){ return sdnLinkPopupMenu; }
	public void setSdnLinkPopupMenu( JPopupMenu sdnLinkPopupMenu ){ this.sdnLinkPopupMenu = sdnLinkPopupMenu; }
	
	private ResultsFrame resultsFrame;
	public ResultsFrame getResultsFrame(){ return resultsFrame; }
	public void setResultsFrame( ResultsFrame resultsFrame ){ this.resultsFrame = resultsFrame; }
	
	public SdnNetworkPlugin( ResultsFrame resultsFrame )
    {
    	super( InputEvent.BUTTON3_MASK );
    	
    	this.setResultsFrame( resultsFrame );
    	
    	this.setSdnNodePopupMenu( new JPopupMenu() );
    	this.setSdnLinkPopupMenu( new JPopupMenu() );
    }
    
    @Override
	@SuppressWarnings("unchecked")
    protected void handlePopup( MouseEvent mouseEvent )
    {
    	VisualizationViewer< Node, Link > visualizationViewer = (VisualizationViewer< Node, Link >) mouseEvent.getSource();
        
    	SdnNode sdnNode = (SdnNode) visualizationViewer.getPickSupport().getVertex( visualizationViewer.getGraphLayout(), mouseEvent.getPoint().getX(), mouseEvent.getPoint().getY() );
    	this.setSdnNode( sdnNode );
    	
        SdnLink sdnLink = (SdnLink) visualizationViewer.getPickSupport().getEdge( visualizationViewer.getGraphLayout(), mouseEvent.getPoint().getX(), mouseEvent.getPoint().getY() );
        this.getSdnLink( sdnLink );
        
    	if( sdnNode != null )
    	{
    		this.updateSdnNodePopupMenu( sdnNode );
    		this.getSdnNodePopupMenu().show( visualizationViewer, mouseEvent.getX(), mouseEvent.getY() );
    	}
    	else if( sdnLink != null )	
    	{
    		this.updateSdnLinkPopupMenu( sdnLink );
    		this.getSdnLinkPopupMenu().show( visualizationViewer, mouseEvent.getX(), mouseEvent.getY() );
    	}
    }
    
    private void updateSdnNodePopupMenu( SdnNode sdnNode )
    {
    	this.getSdnNodePopupMenu().removeAll();
		this.getSdnNodePopupMenu().add( this.sdnNodeMenuItem( sdnNode ) );
		
		for( VirtualNode virtualNode: sdnNode.getVirtualNodes() )
		{
			this.getSdnNodePopupMenu().addSeparator();
			this.getSdnNodePopupMenu().add( this.virtualNodeMenuItem( virtualNode ) );
		}
    }
    private JMenuItem sdnNodeMenuItem( SdnNode sdnNode )
    {
    	Icon icon = null;
    	
		if( sdnNode.isSelected() )
			icon = sdnNode.getGreenIcon();
		
		else if( sdnNode.getVirtualNodes().size() != 0 )
			icon = sdnNode.getYellowIcon();
		
		else
			icon = sdnNode.getGreyIcon();
    	
    	String text = null;
		
    	if( sdnNode instanceof SdnRouter || sdnNode instanceof SdnSwitch )
    		text = "<html><b>" + sdnNode.getNetworkName() + ": </b>" + sdnNode.getName() + "<br><b>OS: </b>" + sdnNode.getOS() + "<br><b>CPU: </b>" + sdnNode.getCPU() + "(" + ( sdnNode.getCPU() - sdnNode.getAvailableCPU() ) + ") " + "<b>RAM: </b>" + sdnNode.getRAM() + "(" + ( sdnNode.getRAM() - sdnNode.getAvailableRAM() ) + ") " + "</html>";
    	
    	else if( sdnNode instanceof SdnServer )
    		text = "<html><b>" + sdnNode.getNetworkName() + ": </b>" + sdnNode.getName() + "<br><b>OS: </b>" + sdnNode.getOS() + "<br><b>CPU: </b>" + sdnNode.getCPU() + "(" + ( sdnNode.getCPU() - sdnNode.getAvailableCPU() ) + ") " + "<b>RAM: </b>" + sdnNode.getRAM() + "(" + ( sdnNode.getRAM() - sdnNode.getAvailableRAM() ) + ") " + " <b>STORAGE: </b>" + sdnNode.getStorage() + "(" + ( sdnNode.getStorage() - sdnNode.getAvailableStorage() ) + ")" + "</html>";
    	
    	JMenuItem menuItem = new JMenuItem();
    	menuItem.setIcon( icon );
    	menuItem.setText( text );
    	menuItem.addActionListener( this );
    	
    	return menuItem;
    }
    private JMenuItem virtualNodeMenuItem( VirtualNode virtualNode )
    {
    	Icon icon = null;
    	
		if( virtualNode.isSelected() )
			icon = virtualNode.getGreenIcon();
		else
			icon = virtualNode.getYellowIcon();
    	
    	String text = null;
			
		if( virtualNode instanceof VirtualRouter || virtualNode instanceof VirtualSwitch )
			text = "<html><b>" + virtualNode.getNetworkName() + ": </b>" + virtualNode.getName() + "<br><b>OS: </b>" + virtualNode.getOS() + "<br><b>CPU: </b>" + virtualNode.getCPU() + " <b>RAM: </b>" + virtualNode.getRAM() + "</html>";
		
		else if( virtualNode instanceof VirtualMachine )
			text = "<html><b>" + virtualNode.getNetworkName() + ": </b>" + virtualNode.getName() + "<br><b>OS: </b>" + virtualNode.getOS() + "<br><b>CPU: </b>" + virtualNode.getCPU() + " <b>RAM: </b>" + virtualNode.getRAM() + " <b>STORAGE: </b>" + virtualNode.getStorage() + "</html>";
			        
		JMenuItem menuItem = new JMenuItem();
		menuItem.setName( virtualNode.getName() + "-" +  virtualNode.getNetworkName() );
		menuItem.setIcon( icon );
		menuItem.setText( text );
		menuItem.addActionListener( this );
        	
		return menuItem;
    }
	
    private void updateSdnLinkPopupMenu( SdnLink sdnLink )
    {
		this.getSdnLinkPopupMenu().removeAll();
		this.getSdnLinkPopupMenu().add( this.sdnLinkMenuItem( sdnLink ) );
		
    	if( sdnLink.getVirtualLinksBWbackupFlags().size() > 0 )
    	{
	    	Iterator< Entry< VirtualLink, BWbackupFlag > > iterator = sdnLink.getVirtualLinksBWbackupFlags().entrySet().iterator();
			
			while( iterator.hasNext() )
			{
				this.getSdnLinkPopupMenu().addSeparator();
				this.getSdnLinkPopupMenu().add( this.virtualLinkMenuItem( iterator.next() ) );
			}
    	}
    }
    private JMenuItem sdnLinkMenuItem( SdnLink sdnLink )
    {
		Node firstNode = sdnLink.getFirstNode();
    	Node secondNode = sdnLink.getSecondNode();
		
    	JMenuItem menuItem = new JMenuItem();
    	menuItem.setText( "<html><b>" + sdnLink.getNetworkName() + ": </b>" + sdnLink.getName() + " <b>BW: </b> " + sdnLink.getBW() + "(" + ( sdnLink.getBW() - sdnLink.getAvailableBW() ) + ")" + "<br><b>Endpoints: </b>" + firstNode.getName() + "-" + secondNode.getName() + "<br><b>Distance: </b>" + sdnLink.getDistance() + "</html>" );
    	menuItem.setIcon( sdnLink.getIcon() );
    	menuItem.addActionListener( this );
    	
    	return menuItem;
    }
    private JMenuItem virtualLinkMenuItem( Entry< VirtualLink, BWbackupFlag > virtualLinkBWbackupFlag )
    {
    	VirtualLink virtualLink = virtualLinkBWbackupFlag.getKey();
		Node firstVirtualNode = virtualLink.getFirstNode();
		Node secondVirtualNode = virtualLink.getSecondNode();
		
		JMenuItem menuItem = new JMenuItem();
		menuItem.setIcon( virtualLink.getIcon() );
		menuItem.setName( virtualLink.getName() + "-" + virtualLink.getNetworkName() );
    	
		if( virtualLinkBWbackupFlag.getValue().getBackupFlag() == 0 )
			menuItem.setText( "<html><b>" + virtualLink.getNetworkName() + ": </b>" + virtualLink.getName() + " <b>BW:</b> " + virtualLink.getBW() + "<br><b>Endpoints: </b>" + firstVirtualNode.getName() + "-" + secondVirtualNode.getName() + "<br><b>Backup: </b>No" + " <b>BW: </b>" + virtualLinkBWbackupFlag.getValue().getBW() + "</html>" );
		
		else if( virtualLinkBWbackupFlag.getValue().getBackupFlag() == 1 )
			menuItem.setText( "<html><b>" + virtualLink.getNetworkName() + ": </b>" + virtualLink.getName() + " <b>BW:</b> " + virtualLink.getBW() + "<br><b>Endpoints: </b>" + firstVirtualNode.getName() + "-" + secondVirtualNode.getName() + "<br><b>Backup: </b>Yes" + " <b>BW: </b>" + virtualLinkBWbackupFlag.getValue().getBW() + "</html>" );
		
		menuItem.addActionListener( this );
    	
		return menuItem;
    }
    
    @Override
	public void actionPerformed( ActionEvent actionEvent )
	{
		this.deselectSdnNetworks();
		this.deselectVirtualNetworks();
		
		SdnNode sdnNode = this.getSdnNode();
		SdnLink sdnLink = this.getSdnLink();
		String menuItemName = ( (JMenuItem) actionEvent.getSource() ).getName();
		
		if( sdnNode != null )
		{
			sdnNode.setSelected( true );
			
			if( menuItemName != null )
			{
				VirtualNode mappedVirtualNode = null;
				
				for( VirtualNode virtualNode: sdnNode.getVirtualNodes() )
					if( virtualNode.getName().equals( menuItemName.split( "-" )[ 0 ] ) && virtualNode.getNetworkName().equals( menuItemName.split( "-" )[ 1 ] ) )
					{
						mappedVirtualNode = virtualNode;
						break;
					}
				
				VirtualNetwork virtualNetwork = this.virtualNetwork( mappedVirtualNode.getNetworkName(), mappedVirtualNode.getTimeStamp() );
					
				if( virtualNetwork.getTimeStamp() == mappedVirtualNode.getTimeStamp() )
					for( VirtualNode virtualNode: virtualNetwork.getVirtualNodes() )
						if( virtualNode.getNumber() == mappedVirtualNode.getNumber() )
						{
							mappedVirtualNode.setSelected( true );
								
							virtualNode.setSelected( true );
							virtualNode.getSdnNode().setSelected( true );
							break;
						}
			}
		}
		else if( sdnLink != null )
		{
			sdnLink.setSelected( true );
			sdnLink.getFirstNode().setSelected( true );
			sdnLink.getSecondNode().setSelected( true );
			
			if( menuItemName != null )
			{
				String virtualLinkName = menuItemName.split( "-" )[ 0 ];
				String virtualLinkNetworkName = menuItemName.split( "-" )[ 1 ];
				
				Iterator< Entry< VirtualLink, BWbackupFlag > > iterator = sdnLink.getVirtualLinksBWbackupFlags().entrySet().iterator(); 
				VirtualLink mappedVirtualLink = null;
				
				while( iterator.hasNext() )
				{
					mappedVirtualLink = iterator.next().getKey();
					
					if( mappedVirtualLink.getNetworkName().equals( virtualLinkNetworkName ) )
						break;
				}
				
				VirtualNetwork virtualNetwork = this.virtualNetwork( mappedVirtualLink.getNetworkName() , mappedVirtualLink.getTimeStamp() );
				
				for( VirtualLink virtualLink: virtualNetwork.getVirtualLinks() )
					if( virtualLink.getName().equals( virtualLinkName ) && virtualLink.getNetworkName().equals( virtualLinkNetworkName ) )
					{
						virtualLink.setSelected( true );
						virtualLink.getFirstNode().setSelected( true );
						virtualLink.getSecondNode().setSelected( true );
						break;
					}
			}
		}
		
		this.getResultsFrame().getSdnNetworksViewersPanelsTabbedPane().repaint();
		this.getResultsFrame().getVirtualNetworksViewersPanelsTabbedPane().repaint();
	}
    private void deselectSdnNetworks()
	{
		List< SdnNetworkViewersPanel > sdnNetworkVisualizationViewersPanels = this.getResultsFrame().getSdnNetworksViewersPanels();
		
		for( int i = 0; i < sdnNetworkVisualizationViewersPanels.size(); i++ )
		{
			List< SdnNetwork > sdnNetworks = sdnNetworkVisualizationViewersPanels.get( i ).getSdnNetworks();
			
			for( int j = 0; j < sdnNetworks.size(); j++ )
			{
				SdnNetwork sdnNetwork = sdnNetworks.get( j );
				
				for( SdnNode sdnNode: sdnNetwork.getSdnNodes() )
				{
					sdnNode.setSelected( false );
					
					for( VirtualNode virtualNode: sdnNode.getVirtualNodes() )
						virtualNode.setSelected( false );
				}
				
				for( SdnLink sdnLink: sdnNetwork.getSdnLinks() )
					sdnLink.setSelected( false );
			}
		}
	}
    private void deselectVirtualNetworks()
	{
		List< VirtualNetworkViewersPanel > virtualNetworkVisualizationViewersPanels = this.getResultsFrame().getVirtualNetworksViewersPanels();
		
		for( int i = 0; i < virtualNetworkVisualizationViewersPanels.size(); i++ )
		{
			List< VirtualNetwork > virtualNetworks = virtualNetworkVisualizationViewersPanels.get( i ).getVirtualNetworks();
			
			for( int j = 0; j < virtualNetworks.size(); j++ )
			{
				VirtualNetwork virtualNetwork = virtualNetworks.get( j );
				
				for( VirtualNode virtualNode: virtualNetwork.getVirtualNodes() )
					virtualNode.setSelected( false );
				
				for( VirtualLink virtualLink: virtualNetwork.getVirtualLinks() )
					virtualLink.setSelected( false );
			}
		}
	}
    private VirtualNetwork virtualNetwork( String virtualNetworkName, int timeInstant )
	{
		JTabbedPane virtualNetworksVisualizationViewersTabbedPane = this.getResultsFrame().getVirtualNetworksViewersPanelsTabbedPane();
		int indexOfTab = virtualNetworksVisualizationViewersTabbedPane.indexOfTab( virtualNetworkName );
		virtualNetworksVisualizationViewersTabbedPane.setSelectedIndex( indexOfTab );
		
		VirtualNetworkViewersPanel virtualNetworkVisualizationViewersPanel = this.getResultsFrame().getVirtualNetworksViewersPanels().get( indexOfTab );
		List< VirtualNetwork > virtualNetworks = virtualNetworkVisualizationViewersPanel.getVirtualNetworks();
		
		for( int i = 0; i < virtualNetworks.size(); i++ )
			if( virtualNetworks.get( i ).getTimeStamp() == timeInstant )
			{
				virtualNetworkVisualizationViewersPanel.putValueSliderss( i );
				return virtualNetworks.get( i );
			}
		
		return null;
	}

}
